package com.ht.modules.system.config;

import com.ht.modules.system.shiro.authc.ShiroRealm;
import com.ht.modules.system.shiro.authc.aop.JwtFilter;
import jakarta.servlet.Filter;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * shiro 配置类
 */

@Configuration
public class ShiroConfig {

    /**
     * Filter Chain定义说明
     * <p>
     * 1、一个URL可以配置多个Filter，使用逗号分隔
     * 2、当设置多个过滤器时，全部验证通过，才视为通过
     * 3、部分过滤器可指定参数，如perms，roles
     */
    @Bean("shiroFilterFactoryBean")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 拦截器
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        // 配置不会被拦截的链接 顺序判断
        // 登录接口排除
        filterChainDefinitionMap.put("/sys/login", "anon");
        // 登录接口排除
        filterChainDefinitionMap.put("/sys/verifyToken", "anon");
        // 登录验证码
        filterChainDefinitionMap.put("/auth/2step-code", "anon");
        // 图片预览不限制token
        filterChainDefinitionMap.put("/sys/common/view/**", "anon");
        // 文件下载不限制token
        filterChainDefinitionMap.put("/sys/common/download/**", "anon");
        // pdf预览
        filterChainDefinitionMap.put("/sys/common/pdf/**", "anon");
        // pdf预览需要文件
        filterChainDefinitionMap.put("/generic/**", "anon");
        filterChainDefinitionMap.put("/", "anon");
        filterChainDefinitionMap.put("/doc.html", "anon");
        filterChainDefinitionMap.put("/**/*.js", "anon");
        filterChainDefinitionMap.put("/**/*.css", "anon");
        filterChainDefinitionMap.put("/**/*.html", "anon");
        filterChainDefinitionMap.put("/**/*.svg", "anon");
        filterChainDefinitionMap.put("/**/*.jpg", "anon");
        filterChainDefinitionMap.put("/**/*.png", "anon");
        filterChainDefinitionMap.put("/**/*.ico", "anon");
        filterChainDefinitionMap.put("/druid/**", "anon");
        filterChainDefinitionMap.put("/swagger-ui.html", "anon");
        filterChainDefinitionMap.put("/swagger**/**", "anon");
        filterChainDefinitionMap.put("/webjars/**", "anon");
        filterChainDefinitionMap.put("/v2/**", "anon");
        filterChainDefinitionMap.put("/**/*.doc", "anon");
        filterChainDefinitionMap.put("/**/*.xlsx", "anon");
        filterChainDefinitionMap.put("/**/*.xls", "anon");
        filterChainDefinitionMap.put("/**/*.txt", "anon");

        // 修改密码接口排除
        filterChainDefinitionMap.put("/sys/user/updatePassword", "anon");
        filterChainDefinitionMap.put("/**/*.pdf", "anon");
        filterChainDefinitionMap.put("/**/*.docx", "anon");

        // cas验证登录
        filterChainDefinitionMap.put("/cas/client/validateLogin", "anon");
        filterChainDefinitionMap.put("/phd/**", "anon");
        filterChainDefinitionMap.put("/decision/**", "anon");
        // 注册用户相关
        filterChainDefinitionMap.put("/user/tempUser/convertToPinYin", "anon");
        filterChainDefinitionMap.put("/user/tempUser/add", "anon");
        filterChainDefinitionMap.put("/user/tempUser/checkUserName", "anon");

        // 性能监控
        filterChainDefinitionMap.put("/actuator/metrics/**", "anon");
        filterChainDefinitionMap.put("/actuator/httptrace/**", "anon");
        filterChainDefinitionMap.put("/actuator/redis/**", "anon");
        filterChainDefinitionMap.put("/WebReport/**", "anon");

        // 表单设计器
        // 自定义表单
        filterChainDefinitionMap.put("/desform/**", "anon");

        // 流程模块组件请求
        filterChainDefinitionMap.put("/act/process/**", "anon");
        filterChainDefinitionMap.put("/act/task/**", "anon");
        filterChainDefinitionMap.put("/act/model/**", "anon");
        filterChainDefinitionMap.put("/service/editor/**", "anon");
        filterChainDefinitionMap.put("/service/model/**", "anon");
        filterChainDefinitionMap.put("/service/model/**/save", "anon");
        filterChainDefinitionMap.put("/editor-app/**", "anon");
        filterChainDefinitionMap.put("/diagram-viewer/**", "anon");
        filterChainDefinitionMap.put("/modeler.html", "anon");
        filterChainDefinitionMap.put("/designer", "anon");
        filterChainDefinitionMap.put("/designer/**", "anon");
        filterChainDefinitionMap.put("/plug-in/**", "anon");
        filterChainDefinitionMap.put("/process/extActProcess/startMutilProcess", "anon");
        // 排除Online请求
        filterChainDefinitionMap.put("/auto/cgform/**", "anon");
        // 生成apk二维码
        filterChainDefinitionMap.put("/apk/sysApk/generateQrCode", "anon");
        // 查询最新版本的apk
        filterChainDefinitionMap.put("/apk/sysApk/queryNewVersion", "anon");
        filterChainDefinitionMap.put("/cas/api/**", "anon");

        // 添加自己的过滤器并且取名为jwt
        Map<String, Filter> filterMap = new HashMap<>(1);
        filterMap.put("jwt", new JwtFilter());
        shiroFilterFactoryBean.setFilters(filterMap);
        // <!-- 过滤链定义，从上向下顺序执行，一般将/**放在最为下边
        filterChainDefinitionMap.put("/**", "jwt");

        // 未授权界面返回JSON
        shiroFilterFactoryBean.setUnauthorizedUrl("/sys/common/403");
        shiroFilterFactoryBean.setLoginUrl("/sys/common/403");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    @Bean("securityManager")
    public DefaultWebSecurityManager securityManager(ShiroRealm myRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myRealm);
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);
        return securityManager;
    }

    /**
     * 下面的代码是添加注解支持
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

}
